package study.eggs.springcloud.gateway.support.utils;

import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpCookie;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;

import java.util.Map;
import java.util.Objects;

@Slf4j
public final class WebUtils {

    public static final String X_REQUEST_ID = "X-Request-Id";

    private WebUtils() {
    }

    /**
     * 获取 ServerHttpRequest
     *
     * @param exchange ServerWebExchange
     * @return ServerHttpRequest
     */
    public static ServerHttpRequest getHttpRequest(ServerWebExchange exchange) {
        ServerHttpRequest request = exchange.getRequest();
        return request;
    }

    /**
     * 获取 ServerHttpResponse
     *
     * @param exchange ServerWebExchange
     * @return ServerHttpResponse
     */
    public static ServerHttpResponse getHttpResponse(ServerWebExchange exchange) {
        ServerHttpResponse response = exchange.getResponse();
        return response;
    }

    /**
     * 是否为只读 Header
     *
     * @param headers
     * @return boolean
     */
    public static boolean isReadOnly(HttpHeaders headers) {
        //class package access, so routing by name
        String cName = headers.getClass().getSimpleName();
        return Objects.equals("ReadOnlyHttpHeaders", cName);
    }

    /**
     * 获取请求头
     */
    public static String getRequestHeader(ServerWebExchange exchange, String name) {
        ServerHttpRequest request = getHttpRequest(exchange);
        HttpHeaders headers = request.getHeaders();
        String value = null;
        if (Objects.nonNull(headers)) {
            value = headers.getFirst(name);
        }
        return value;
    }

    /**
     * 获取响应头
     */
    public static String getResponseHeader(ServerWebExchange exchange, String name) {
        ServerHttpResponse response = getHttpResponse(exchange);
        HttpHeaders headers = response.getHeaders();
        String value = null;
        if (Objects.nonNull(headers)) {
            value = headers.getFirst(name);
        }
        return value;
    }

    /**
     * 添加请求头
     */
    public static void addRequestHeader(ServerWebExchange exchange, String name, String value) {
        Map<String, String> header = Maps.newHashMap();
        header.put(name, value);
        addRequestHeaders(exchange, header);
    }

    public static void addRequestHeaders(ServerWebExchange exchange, Map<String, String> headerMap) {
        ServerHttpRequest request = getHttpRequest(exchange);
        HttpHeaders headers = request.getHeaders();
        if (Objects.nonNull(headers) && isReadOnly(headers)) {
            //log.warn("readonly request header, so mutate");
            request.mutate().headers(myHeaders -> {
                headerMap.entrySet().stream()
                        .forEach(e -> myHeaders.add(e.getKey(), e.getValue()));
            }).build();
        } else {
            headerMap.entrySet().stream()
                    .forEach(e -> headers.add(e.getKey(), e.getValue()));
        }
    }


    /**
     * 添加响应头
     */
    public static void addResponseHeader(ServerWebExchange exchange, String name, String value) {
        Map<String, String> headerMap = Maps.newHashMap();
        headerMap.put(name, value);
        addResponseHeader(exchange, headerMap);
    }

    public static void addResponseHeader(ServerWebExchange exchange, Map<String, String> headerMap) {
        ServerHttpResponse response = getHttpResponse(exchange);
        HttpHeaders headers = response.getHeaders();
        if (Objects.nonNull(headers) && isReadOnly(headers)) {
            //log.warn("readonly response header, so bad");
            headerMap.entrySet().stream().forEach(e -> {
                headers.add(e.getKey(), e.getValue());
            });
        } else {
            headerMap.entrySet().stream().forEach(e -> {
                headers.add(e.getKey(), e.getValue());
            });
        }
    }

    /**
     * 获取 Cookie
     *
     * @param exchange
     * @param name
     * @return String
     */
    public static String getCookieValue(ServerWebExchange exchange, String name) {
        ServerHttpRequest request = getHttpRequest(exchange);
        MultiValueMap<String, HttpCookie> cookies = request.getCookies();
        String value = null;
        if (Objects.nonNull(cookies)) {
            HttpCookie cookie = cookies.getFirst(name);
            if (Objects.nonNull(cookie)) {
                value = cookie.getValue();
            }
        }
        return value;
    }

    /**
     * 获取 Request Id
     *
     * @param exchange
     * @return String
     */
    public static String getRequestId(ServerWebExchange exchange) {
        return getRequestHeader(exchange, X_REQUEST_ID);
    }
}
